Skip to content

Enable deploy from url with token - #1928

Open
s-yonkov-yonkov wants to merge 5 commits into
masterfrom
feature/LMCROSSITXSADEPLOY-3391
Open

s-yonkov-yonkov wants to merge 5 commits into
masterfrom
feature/LMCROSSITXSADEPLOY-3391

Conversation

@s-yonkov-yonkov

Copy link
Copy Markdown
Contributor

No description provided.

…ROSSITXSADEPLOY-3391]

Add bearer token support to the deploy-from-URL feature so MTA archives
hosted on GitHub (release assets, raw content) can be fetched using a
GitHub PAT or GITHUB_TOKEN.

Changes:
- UserCredentials: add optional `token` field (additive, backward compatible)
- Introduce RequestAuthenticator strategy (Bearer, Basic, UrlUserInfo, None)
  with explicit precedence: token > basic > url-userinfo > none
- AuthenticatorResolver injected as a @nAmed Spring bean into
  DeployFromUrlRemoteClient (replaces inline if/else ladder)
- Fix pre-existing audit-log leak: logStartUploadFromUrl now receives the
  userinfo-stripped URL instead of the raw decoded URL
- Tests: AuthenticatorResolverTest (9), DeployFromUrlRemoteClientTest (+2),
  FilesApiServiceImplTest (+1 audit-log regression test)

# Conflicts:
#	multiapps-controller-web/src/main/java/org/cloudfoundry/multiapps/controller/web/upload/client/DeployFromUrlRemoteClient.java
#	multiapps-controller-web/src/test/java/org/cloudfoundry/multiapps/controller/web/upload/client/DeployFromUrlRemoteClientTest.java
@s-yonkov-yonkov
s-yonkov-yonkov force-pushed the feature/LMCROSSITXSADEPLOY-3391 branch from a26345c to e0c63ee Compare October 16, 2026 13:36
@sonarqubecloud

Copy link
Copy Markdown

Comment on lines 97 to 113
private HttpResponse<InputStream> followRedirectsWithValidation(String url, String jobId, UserCredentials userCredentials,
int redirectCount) throws Exception {
if (redirectCount > MAX_REDIRECTS) {
throw new SLException(MessageFormat.format(Messages.ERROR_FROM_REMOTE_MTAR_ENDPOINT_FOR_JOB_WITH_ID,
getMaskedUri(urlDecodeUrl(url)), Messages.TOO_MANY_REDIRECTS, "", jobId));
}
HttpRequest request = buildFetchFileRequest(url, userCredentials);
HttpResponse<InputStream> response = httpClient.send(request, HttpResponse.BodyHandlers.ofInputStream());
int status = response.statusCode();
if (isRedirect(status)) {
return followRedirect(response, url, jobId, userCredentials, redirectCount);
}
if (status < 200 || status >= 300) {
throwErrorResponseException(response, url, status, jobId);
throwErrorResponseException(response, url, status, jobId, userCredentials);
}
return response;
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Each redirect re-sends the token to the new target using the same userCredentials, and nothing checks whether the redirect host matches the original. As a result, a redirect to any public host still receives the Authorization: Bearer header.

Could we drop the Authorization header when a redirect crosses hosts and only preserve it for same-host redirects? Will this break this scenario?

return response;
}
@Test
void downloadFileFromUrlWithTokenSendsBearer() throws Exception {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This checks the Authorization header on a single request. The existing redirectToPublicAddressIsFollowed verifies the hops are validated but never inspects the header after a redirect, so nothing covers which credentials reach the second hop. Could we add a cross-host redirect case that asserts that?

Comment on lines +27 to +31
if (StringUtils.isNotBlank(userCredentials.getToken())) {
return new BearerTokenAuthenticator(userCredentials.getToken());
}
return new BasicAuthenticator(userCredentials.getUsername(), userCredentials.getPassword());
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The token branch guards with isNotBlank, but Basic doesn't. Since the fields are @Nullable, could Basic fall through to no-auth when username/password are blank, like the token branch does?

Comment on lines +141 to +148
if (status == HttpStatus.FORBIDDEN.value()) {
throw new SLException(MessageFormat.format(Messages.DEPLOY_FROM_URL_FORBIDDEN,
UriUtil.stripUserInfo(url)));
}
if (status == HttpStatus.NOT_FOUND.value() && hasToken(userCredentials)) {
throw new SLException(MessageFormat.format(Messages.DEPLOY_FROM_URL_NOT_FOUND_WITH_TOKEN,
UriUtil.stripUserInfo(url)));
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The 404 branch checks hasToken before mentioning the token, but the 403 branch doesn't. A 403 with no token still says "make sure the provided token has the required permissions." Could we guard the 403 message with hasToken too?

Comment on lines +26 to +27
public static final String DEPLOY_FROM_URL_FORBIDDEN = "Access to {0} is forbidden. Make sure the provided token has the required permissions.";
public static final String DEPLOY_FROM_URL_NOT_FOUND_WITH_TOKEN = "The resource at {0} was not found. If it is private, verify the provided token is valid and has read access.";

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The other deploy-from-URL errors append the job id for traceability, but these two drop it. Could we keep the pattern so the failures can be correlated in the logs?

}

@Test
void downloadFileFromUrlForbiddenWithTokenReturnsCorrectError() throws Exception {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These three error tests repeat the same status->body->send stub. A small stubErrorResponse(status, body) would fold that together, the way stubSuccessfulHttpResponse already does for the 200 case.

Comment on lines 343 to +344
}
@Test

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing blank line here

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants